﻿using System;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Newtonsoft.Json;
using NymphsLib.CommonUtilities;
using NymphsLib.CommonUtilities.Components;
using NymphsLib.CommonUtilities.FileSystem;
using ETP.VisualEditor.UI;
using MovieBrowser.Controller;
using MovieBrowser.Event;
using MovieBrowser.Model;
using MovieBrowser.Parser;
using MovieBrowser.Presentation.Browser;
using MovieBrowser.Presentation.Forms.Db;
using MovieBrowser.Presentation.Forms.Dialogs;
using MovieBrowser.Util;
using NymphsLib.ShellLib;
using NavigateEventArgs = MovieBrowser.Event.NavigateEventArgs;
using System.Collections.Generic;
using MovieBrowser.Presentation.List;
using System.Xml.Serialization;
using System.Text;
using System.Xml;
using CefSharp.WinForms;
using CefSharp;
using Formatting = System.Xml.Formatting;


namespace MovieBrowser.Presentation.Forms
{
    public partial class MainAppForm : Form
    {
        private readonly SaveFileDialog _saveFileDialog = new SaveFileDialog();
        private readonly OpenFileDialog _openFileDialog = new OpenFileDialog();
        private readonly FolderBrowserDialog _folderBrowserDialog = new FolderBrowserDialog();
        private MovieBrowserController _controller = new MovieBrowserController();
        private readonly CopyQueueForm _copyQueueForm = new CopyQueueForm();

        public MainAppForm()
        {
            var settings = new CefSharp.CefSettings()
            {
                PackLoadingDisabled = true,
            };
            Cef.Initialize(settings);


            InitializeComponent();
            LoadController();
            ImdbParser.LoadRules(Properties.Settings.Default.ImdbRules);

            // List Movie Database
            _listAllMoviesDB.MovieSelectionChange += ListViewListViewListViewSelectionChange;
            _listAllMoviesDB.CopyMovies += ListViewCopy;
            _listAllMoviesDB.Enqueue += ListViewEnqueue;
            _listAllMoviesDB.DebugText += DebugTextFired;

            // FileSystem
            _listFileSystem.MovieSelectionChange += ListViewListViewListViewSelectionChange;
            _listFileSystem.CopyMovies += TreeViewFileSystemCopy;
            _listFileSystem.Enqueue += ListViewEnqueue;
            _listFileSystem.DebugText += DebugTextFired;

            // Search
            _listSearch.CopyMovies += ListViewCopy;
            _listSearch.MovieSelectionChange += ListViewListViewListViewSelectionChange;
            _listSearch.Enqueue += ListViewEnqueue;
            _listSearch.DebugText += DebugTextFired;

            // PersonList
            _personListDbAll.MovieSearch += ImdbInfoMovieSearch;
            _personListDbAll.DebugText += DebugTextFired;

            _webBrowser.UpdateMovie += WebBrowserUpdateMovie;
            //_webBrowser.AddMovie += WebBrowserUpdateMovie;
            //Navigate
            _imdbInfo.MovieSearch += ImdbInfoMovieSearch;
            _imdbInfo.NavigateWeb += NavigateWeb;
            //
            imdbStatus.MovieSearch += ImdbInfoMovieSearch;
            imdbStatus.NavigateWeb += NavigateWeb;
            imdbStatus.NoteChange += ImdbStatusNoteChange;
            //Debug
            _imdbInfo.DebugText += DebugTextFired;
            _webBrowser.DebugText += DebugTextFired;
            imdbStatus.DebugText += DebugTextFired;
            _copyQueueForm.DebugText += DebugTextFired;
        }

        private void ImdbStatusNoteChange(object sender, EventArgs e)
        {
            var eventArgs = (PersonalNoteUpdateEventArgs)e;


            if (eventArgs.Note == Note.Wishlist)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.ToggleOrSetWishlist(Authorization.LoggedInUser, selectedMovie, (bool)eventArgs.Data);
                }
            }
            else if (eventArgs.Note == Note.Like)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.SetFavourite(Authorization.LoggedInUser, selectedMovie, true, (int)eventArgs.Data);
                }
            }
            else if (eventArgs.Note == Note.Dislike)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.SetFavourite(Authorization.LoggedInUser, selectedMovie, false, (int)eventArgs.Data);
                }
            }
            else if (eventArgs.Note == Note.Seen)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.ToggleOrSetSeenIt(Authorization.LoggedInUser, selectedMovie, (bool)eventArgs.Data);
                }
            }
            else if (eventArgs.Note == Note.Have)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.ToggleOrSetHaveIt(Authorization.LoggedInUser, selectedMovie, (bool)eventArgs.Data);
                }
            }
            else if (eventArgs.Note == Note.UserListAdd)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.AddToUserList(selectedMovie, (long)eventArgs.Data);
                }
            }
            else if (eventArgs.Note == Note.UserListRemove)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.RemoveFromUserList(selectedMovie, (long)eventArgs.Data);
                }
            }
            else if (eventArgs.Note == Note.Subtitle)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.UpdateSubtitle(selectedMovie, (bool)eventArgs.Data);
                }
            }
            else if (eventArgs.Note == Note.Rating)
            {
                foreach (var selectedMovie in SelectedMovies)
                {
                    _controller.UpdateUserRating(Authorization.LoggedInUser, selectedMovie, (double)eventArgs.Data);
                }
            }
        }

        private void ListViewEnqueue(object sender, EventArgs e)
        {
            var args = (CopyMoviesEventArgs)e;
            _copyQueueForm.AddToQueue(args.Movies);
        }

        private void ListViewCopy(object sender, EventArgs e)
        {
            var args = (CopyMoviesEventArgs)e;
            if (comboPendrives.Text != null)
            {
                MovieBrowserController.SendTo(args.Movies, comboPendrives.Text, OverwritePolicy.Ask);
            }
            else
            {
                MessageBox.Show(@"No destination selected.");
            }
        }

        private void TreeViewFileSystemCopy(object sender, EventArgs e)
        {
            var args = (CopyMoviesEventArgs)e;
            if (comboPendrives.Text != null)
            {
                MovieBrowserController.SendTo(args.Movies, comboPendrives.Text, OverwritePolicy.Ask);
                _listFileSystem.ClearCheckedItems();
            }
            else
            {
                MessageBox.Show(@"No destination selected.");
            }
        }

        private void NavigateWeb(object sender, EventArgs e)
        {
            var ee = e as NavigateEventArgs;
            if (ee != null)
            {
                tabInformation.SelectedIndex = 0;
                if (ee.IsNewTab)
                    _webBrowser.NavigateNew(ee.Address);
                else
                {
                    _webBrowser.Navigate(ee.Address);
                }
            }
        }

        private void ImdbInfoMovieSearch(object sender, EventArgs e)
        {
            var csea = e as CriteriaSearchEventArgs;
            if (csea != null)
            {
                _listSearch.LoadResults(csea.Movies);
                tabMovies.SelectedTab = tpSearch;
            }
        }

        #region ThreadSafe Access

        private void DebugTextFired(object sender, EventArgs e)
        {
            if (textBox1.InvokeRequired)
            {
                textBox1.Invoke(new EventHandler(DebugTextFired), sender, e);
            }
            else
            {
                var ee = e as DebugTextEventArgs;
                if (ee != null)
                    if (ee.Data != null)
                    {
                        textBox1.InsertTextAsRtf(e.ToString(), textBox1.Font, RtfColor.Red);
                    }
                    else
                    {
                        textBox1.AppendText(ee.ToString());
                    }
            }
        }


        private void OnDesktopNotify(object sender, EventArgs e)
        {
            notifyIcon1.BalloonTipTitle = ((DebugTextEventArgs)e).Title;
            notifyIcon1.BalloonTipText = ((DebugTextEventArgs)e).Text;
            notifyIcon1.ShowBalloonTip(200);
        }

        #endregion

        private void WebBrowserUpdateMovie(object sender, EventArgs e)
        {
            try
            {
                var browser = sender as MovieWebBrowser;
                var movie = SelectedMovie;
                var html = _webBrowser.Html;

                if (browser == null) return;
                var t = new Thread(() =>
                                       {
                                           var parsedMovie = ImdbParserHelper.ToMovie(ImdbParser.ParseMovie(html));
//                                           var xmlSerializer = new XmlSerializer(typeof(Movie));
//                                           string xmlText;
//                                           var memoryStream = new MemoryStream();
//                                           using (var xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8) { Formatting = Formatting.Indented })
//                                           {
//                                               xmlSerializer.Serialize(xmlTextWriter, parsedMovie);
//                                               memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
//                                               xmlText = new UTF8Encoding().GetString(memoryStream.ToArray());
//                                               memoryStream.Dispose();
//                                           }
                                           string serialized = JsonConvert.SerializeObject(parsedMovie, Newtonsoft.Json.Formatting.Indented);

                                           //DebugTextFired(sender, new DebugTextEventArgs(xmlText));
                                           DebugTextFired(sender, new DebugTextEventArgs(serialized));
                                           _controller.UpdateMovieNode(movie, parsedMovie);
                                       });
                t.Start();
            }
            catch (Exception exp)
            {
                Logger.Exception(exp, 251, "WebBrowserUpdateMovie");
            }
        }

        public IMovieList ActiveMovieList
        {
            get
            {
                if (tabMovies.SelectedTab == tpMoviesTree)
                {
                    return _listFileSystem;
                }
                //                if (tabMovies.SelectedTab == tpVirtualFolders)
                //                {
                //                    return _movieListVirtualTree;
                //                }
                if (tabMovies.SelectedTab == tpMoviesDb)
                {
                    return _listAllMoviesDB;
                }
                if (tabMovies.SelectedTab == tpSearch)
                {
                    return _listSearch;
                }
                return null;
            }
        }

        public IListUI ActiveList
        {
            get
            {
                if (tabMovies.SelectedTab == tpMoviesTree)
                {
                    return _listFileSystem;
                }
                //                else if (tabMovies.SelectedTab == tpVirtualFolders)
                //                {
                //                    return _movieListVirtualTree;
                //                }
                if (tabMovies.SelectedTab == tpMoviesDb)
                {
                    return _listAllMoviesDB;
                }
                if (tabMovies.SelectedTab == tpSearch)
                {
                    return _listSearch;
                }
                if (tabMovies.SelectedTab == tpPerson)
                {
                    return _personListDbAll;
                }
                return null;
            }
        }

        protected IList<Movie> SelectedMovies
        {
            get
            {
                if (ActiveMovieList != null)
                    return ActiveMovieList.SelectedMovies;
                return new List<Movie>();
            }
        }

        protected Movie SelectedMovie
        {
            get
            {
                if (ActiveMovieList != null)
                    return ActiveMovieList.SelectedMovie;
                return null;
            }
        }

        private void ListViewListViewListViewSelectionChange(object sender, EventArgs e)
        {
            var args = (MovieEventArgs)e;
            imdbStatus.LoadMovie(args.Movie);
            _imdbInfo.LoadMovie(args.Movie);
        }

        private KeywordsForm _keywordsForm;

        private void MovieBrowserFormLoad(object sender, EventArgs e)
        {
            LoadColors();
            Login();
            _listAllMoviesDB.LoadMovies();
            MovieBrowserController.LoadPenDrives(comboPendrives);

            SetDetailsView(Properties.Settings.Default.DetailsView, false);
        }

        private static void LoadColors()
        {
            if (Properties.Settings.Default.Foregrounds != null)
            {
                for (var i = 0; i < Properties.Settings.Default.Foregrounds.Count; i++)
                {
                    var foreground = Properties.Settings.Default.Foregrounds[i];
                    var background = Properties.Settings.Default.Backgrounds[i];

                    ComponentUtility.HardnessForeground[i] = ColorTranslator.FromHtml(foreground);
                    ComponentUtility.HardnessBackground[i] = ColorTranslator.FromHtml(background);
                }
            }
        }

        private void Login()
        {
            if (Authorization.Instance == null)
            {
                var form = new LoginForm(_controller.Db);
                form.LoggedIn += (sender, args) =>
                                     {
                                         var textEventArgs = (DebugTextEventArgs)args;
                                         if (textEventArgs.Data != null)
                                             Authorization.CreateInstance(textEventArgs.Data as User);
                                     };
                form.ShowDialog(this);
            }

            _listSearch.LoadUserList();
            imdbStatus.LoadUserList();
        }


        private IgnoreListForm _ignoreListForm;

        private void LoadController()
        {
            _controller = new MovieBrowserController { IntelligentSearch = true };

            _controller.OnNavigate += NavigateWeb;
            _controller.DebugText += DebugTextFired;
            _controller.OnNotificationFired += OnDesktopNotify;

            _imdbInfo.Controller = _controller;
            imdbStatus.Controller = _controller;
            _listFileSystem.Controller = _controller;
            _listAllMoviesDB.Controller = _controller;
            _listSearch.Controller = _controller;
            //            _movieListVirtualTree.Controller = _controller;
            _webBrowser.Controller = _controller;
            _personListDbAll.Controller = _controller;


            LoadWebLinks();
        }

        private void ReloadLinksToolStripMenuItemClick(object sender, EventArgs e)
        {
            LoadWebLinks();
        }

        private void LoadWebLinks()
        {
            var links = _controller.Db.WebLinks;
            linkToolStripMenuItem.DropDownItems.Clear();
            foreach (var webLink in links)
            {
                ToolStripItem item = new ToolStripButton(webLink.Title);
                var link = webLink;
                item.Click += (sender, e) =>
                                  {
                                      if (SelectedMovie != null)
                                      {
                                          var url = link.Url
                                              .Replace("%t", HttpHelper.UrlEncode(SelectedMovie.Title))
                                              .Replace("%y", SelectedMovie.Year.ToString(CultureInfo.InvariantCulture))
                                              .Replace("%i", SelectedMovie.ImdbId);

                                          new ShellExecute { Path = url, Verb = ShellExecute.OpenFile }.Execute();
                                      }
                                  };
                item.AutoSize = true;
                item.Width = 300;
                linkToolStripMenuItem.DropDownItems.Add(item);
            }
        }

        private void MovieFormToolStripMenuItemClick(object sender, EventArgs e)
        {
            new MovieForm().ShowDialog(this);
        }

        private void WebLinkEditorToolStripMenuItemClick(object sender, EventArgs e)
        {
            new WebLinksForm().ShowDialog(this);
            LoadWebLinks();
        }

        private void MovieGridFormToolStripMenuItemClick(object sender, EventArgs e)
        {
            new MovieGridForm().ShowDialog(this);
        }

        private void RefreshDatabaseToolStripMenuItemClick(object sender, EventArgs e)
        {
            LoadController();
        }

        private void BackupDatabaseToolStripMenuItemClick(object sender, EventArgs e)
        {
            var dbFilelocation = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
                                 @"\MaxInc\Db\MovieDb.sqlite";
            _saveFileDialog.Filter = @"MovieDb|*.sqlite";
            if (_saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                File.Copy(dbFilelocation, _saveFileDialog.FileName, true);
            }
        }

        private void RestoreDatabaseToolStripMenuItemClick(object sender, EventArgs e)
        {
            _openFileDialog.Filter = @"MovieDb|*.sqlite";
            if (_openFileDialog.ShowDialog() == DialogResult.OK)
            {
                var dbFilelocation = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
                                     @"\MaxInc\Db\MovieDb.sqlite";
                File.Copy(_openFileDialog.FileName, dbFilelocation, true);
            }
        }

        private void CleanupToolStripMenuItemClick(object sender, EventArgs e)
        {
            new CleanUpDatabase().Show(this);
            _controller.Refresh();
        }

        private void IgnoreListToolStripMenuItemClick(object sender, EventArgs e)
        {
            if (_ignoreListForm == null) _ignoreListForm = new IgnoreListForm();
            _ignoreListForm.ShowDialog(this);
        }

        private void KeywordsToolStripMenuItemClick(object sender, EventArgs e)
        {
            if (_keywordsForm == null)
                _keywordsForm = new KeywordsForm(_controller.Db);
            _keywordsForm.ShowDialog(this);
        }

        private void LoginToolStripMenuItemClick(object sender, EventArgs e)
        {
            Login();
        }

        private void UsersToolStripMenuItemClick(object sender, EventArgs e)
        {
            Form form = new UsersForm(_controller.Db);
            form.ShowDialog(this);
        }

        private void ExitToolStripMenuItemClick(object sender, EventArgs e)
        {
            Hide();
            Application.Exit();
        }

        private void ColorPreferenceToolStripMenuItemClick(object sender, EventArgs e)
        {
            var colorSetup = new ColorSetup();
            colorSetup.FormClosed += colorSetup_FormClosed;
            colorSetup.Show(this);
        }

        void colorSetup_FormClosed(object sender, FormClosedEventArgs e)
        {
            _listAllMoviesDB.UpdateFont(Properties.Settings.Default.ListFont);
            _listFileSystem.UpdateFont(Properties.Settings.Default.ListFont);
            _listSearch.UpdateFont(Properties.Settings.Default.ListFont);
            //            _movieListVirtualTree.UpdateFont(Properties.Settings.Default.ListFont);
            _personListDbAll.UpdateFont(Properties.Settings.Default.ListFont);
        }

        private void LoadPenDrivesToolStripMenuItemClick(object sender, EventArgs e)
        {
            MovieBrowserController.LoadPenDrives(comboPendrives);
        }

        private void CopyDestinationToolStripMenuItem1Click(object sender, EventArgs e)
        {
            if (_folderBrowserDialog.ShowDialog(this) == DialogResult.OK)
            {
                if (!comboPendrives.Items.Contains(_folderBrowserDialog.SelectedPath))
                {
                    var index = comboPendrives.Items.Add(_folderBrowserDialog.SelectedPath);
                    comboPendrives.SelectedIndex = index;
                }
            }
        }

        private void ShowQueueToolStripMenuItemClick(object sender, EventArgs e)
        {
            _copyQueueForm.ShowDialog(this);
        }

        private void tsViewStatus_Click(object sender, EventArgs e)
        {
            SetDetailsView(tsViewStatus.Checked, true);
        }

        private void tsViewDetailsStatus_Click(object sender, EventArgs e)
        {
            SetDetailsView(!tsViewDetailsStatus.Checked, true);
        }

        void SetDetailsView(bool detailsView, bool save)
        {
            if (save)
            {
                Properties.Settings.Default.DetailsView = detailsView;
                Properties.Settings.Default.Save();
            }
            imdbStatus.DetailsView = detailsView;
            imdbStatus.Height = imdbStatus.DetailsView ? 200 : 50;
            tsViewDetailsStatus.Checked = detailsView;
            tsViewStatus.Checked = !detailsView;
            if (detailsView)
            {
                imdbStatus.LoadUserList();
            }
        }

        private void applicationSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new ApplicationSettingsForm().Show();
        }

        private void exportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var saveFileDialog = new SaveFileDialog();
            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                var file = new StreamWriter(saveFileDialog.FileName);

                var movies = _controller.Db.Movies;
                foreach (var movie in movies)
                {

                    var line = string.Format("{0}\t{1}\t{2}\t{3}", movie.ImdbId, movie.Title, movie.Year, movie.Rating);
                    file.WriteLine(line);
                }
                file.Close();
            }
        }

        private void parserDefinitionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var ofd = new OpenFileDialog();
            if (ofd.ShowDialog(this) == DialogResult.OK)
            {
                Properties.Settings.Default.ImdbRules = ofd.FileName;
                Properties.Settings.Default.Save();
            }
        }

        private void importToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _openFileDialog.Filter = @"Excel Document|*.xlsx";
            if (_openFileDialog.ShowDialog(this) != DialogResult.OK) return;
            var newFile = new FileInfo(_openFileDialog.FileName);
            _controller.ImportExcel(newFile);
        }

        private void tsGroup_Click(object sender, EventArgs e)
        {
            try
            {
                tsGroup.Checked = !tsGroup.Checked;
                ActiveList.ShowGroup(tsGroup.Checked);
            }
            catch { }
        }

        private void graphToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new DbGraph().ShowDialog();
        }

        private void parserEditorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new EasyTextParserEditor()).ShowDialog();
        }

        private void importToolStripMenuItemImport_Click(object sender, EventArgs e)
        {
            _openFileDialog.Filter = @"Excel Document|*.xlsx";
            if (_openFileDialog.ShowDialog(this) != DialogResult.OK) return;
            var newFile = new FileInfo(_openFileDialog.FileName);
            _controller.ImportExcel(newFile);

            //            _openFileDialog.Filter = @"Excel Document|*.xlsx";
            //            if (_openFileDialog.ShowDialog(this) != DialogResult.OK) return;
            //
            //            var newFile = new FileInfo(_saveFileDialog.FileName);
            //            Controller.SaveToExcel(newFile, (from o in Controller.Db.Movies orderby o.Title select o).ToList());
            // 
        }

        private void _movieListSearch_Load(object sender, EventArgs e)
        {

        }
    }
}